package edu.krazy.server;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.Socket;
import java.net.SocketException;
import java.util.LinkedList;

import edu.krazy.common.BasicClientMessage;
import edu.krazy.common.ClientState;
import edu.krazy.common.MessageType;

public class KrazyClient extends Thread {
	private String mUserName;
	private Socket mSocket;
	private IOnClientMessage listener;
	private LinkedList<BasicClientMessage> mQueue;
	private ObjectOutputStream mOutput;
	private ObjectInputStream mInput;
	private boolean mRunning;
	
	public String getUsername(){
		return mUserName;
	}
	
	public IOnClientMessage getListener() {
		return listener;
	}

	public void setListener(IOnClientMessage listener) {
		this.listener = listener;
	}

	public KrazyClient(Socket pSocket) throws IOException{
		mQueue = new LinkedList<BasicClientMessage>();
		mSocket = pSocket;
		mOutput = new ObjectOutputStream(mSocket.getOutputStream());
		mInput = new ObjectInputStream(mSocket.getInputStream());
		mUserName = mInput.readUTF();
	}
	
	public void writeToClient(int msgType, String msg){
		//try {
			mQueue.add(new BasicClientMessage(msgType, msg));
			//mOutput.writeInt(msgType);
			//mOutput.writeUTF(msg);
			//mOutput.flush();
		//} catch (IOException e) {
			// TODO Auto-generated catch block
		//	e.printStackTrace();
		//}
		
	}
	
	public void writeToClient(int msgType, String msg, Object obj){
		//try {
			mQueue.add(new BasicClientMessage(msgType, msg, obj));
			//mOutput.writeInt(msgType);
			//mOutput.writeUTF(msg);
			//mOutput.writeObject(obj);
			//mOutput.flush();
		//} catch (IOException e) {
			// TODO Auto-generated catch block
		//	e.printStackTrace();
		//}
		
	}
	
	public void writeToClient(int msgType){
		mQueue.add(new BasicClientMessage(msgType));
		/*try {
			mOutput.writeInt(msgType);
			mOutput.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}*/
	}

	@Override
	public void run() {
		writeToClient(ClientState.CONNECTED_TO_GAME);
		mRunning = true;
		writeThread.start();
		while(mRunning){
			try {
				switch(mInput.readInt()){
				case MessageType.CREATE_GAME:
					if(listener != null){
						listener.createLobby(this, mInput.readUTF());
					}
					break;
				case MessageType.JOIN_GAME:
					if(listener!=null){
						listener.joinGame(this, mInput.readUTF());
					}
					break;
				case MessageType.READY_GAME:
					if(listener!=null){
						listener.readyGame();
						listener.broadcastMessageType(this, MessageType.READY_GAME);
					}
					break;
				case MessageType.READY_PLAYER:
					System.out.println("MessageType.READY_PLAYER\n");
					if(listener != null){
						listener.readyPlayer(this);
					}
					break;
				case MessageType.BROADCAST_POSITIONS:
					if(listener != null){
						try {
							listener.broadcastObject(this, MessageType.BROADCAST_POSITIONS, mInput.readObject());
						} catch (ClassNotFoundException e) {
							e.printStackTrace();
						}
					}
					break;
				case MessageType.LEAVE_GAME:
					if(listener != null){
						listener.leaveGame(this);
					}
					break;
				}
			} catch (SocketException e){
				//e.printStackTrace();
				mRunning = false;
			}catch (EOFException e){
				//e.printStackTrace();
				mRunning = false;
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		System.out.println("END KRAZY CLIENT\n");
		if(listener!=null){
			listener.clientDisconnected(this);
			listener = null;
		}
		if(!mSocket.isClosed()){
			try {
				mInput.close();
				mOutput.close();
				mSocket.close();	
				mInput = null;
				mOutput = null;
				mSocket = null;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		super.run();
	}
	
	protected void writeMessage(BasicClientMessage message){
		try {
			mOutput.writeInt(message.getType());
			if(message.getData() != null){
				if(message.getData() instanceof String){
					mOutput.writeUTF((String)message.getData());
					if(message.getData2() != null){
						mOutput.writeObject(message.getData2());
					}
				}else if(message.getData() instanceof Integer){
					mOutput.writeInt((Integer)message.getData());
				}else{
					mOutput.writeObject(message.getData());
				}
			}
			mOutput.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private Thread writeThread = new Thread(){

		@Override
		public void run() {
			while (mRunning){
				BasicClientMessage message;
				synchronized (mQueue) {
					if((message = mQueue.poll()) != null){
						writeMessage(message);
					}
				}
			}
			mQueue.clear();
			super.run();
		}
		
	};
	
}
